/*
  Copyright 2019 Google LLC

  Use of this source code is governed by an MIT-style
  license that can be found in the LICENSE file or at
  https://opensource.org/licenses/MIT.
*/

importScripts(
    '/node_modules/mocha/mocha.js',
    '/node_modules/chai/chai.js',
    '/node_modules/sinon/pkg/sinon-no-sourcemaps.js'
);

// Disable workbox logs in test mode.
self.__WB_DISABLE_DEV_LOGS = true;

self.expect = chai.expect;

// TODO(philipwalton): Move these globals back into imports once the
// conversion to run all unit tests in browsers is complete.
self.expectError = async (func, errorName, finalCb) => {
  let caughtError = null;
  try {
    const result = func();
    if (result && result instanceof Promise) {
      await result;
    }
  } catch (err) {
    caughtError = err;
  }

  if (!caughtError) {
    throw new Error('Expected error to be thrown but function ran correctly.');
  }

  if (caughtError.constructor.name !== 'WorkboxError') {
    console.warn(`Unexpected error thrown.`, caughtError);
  }

  expect(caughtError.constructor.name).to.equal('WorkboxError');
  expect(caughtError.name).to.equal(errorName);

  if (finalCb) {
    return finalCb(caughtError);
  }
};
self.waitUntil = async (fn, retries = 20, intervalMillis = 50) => {
  for (let i = 0; i < retries; i++) {
    const result = await fn();
    if (result) {
      return;
    }
    await new Promise((resolve) => setTimeout(resolve, intervalMillis));
  }
  throw new Error(`${fn} didn't return true after ${retries} retries.`);
};


mocha.setup({
  ui: 'bdd',
  timeout: 5000,
  reporter: null,
});

addEventListener('install', (event) => {
  const testsComplete = new Promise((resolve, reject) => {
    const reports = [];
    const runner = mocha.run();

    runner.on('fail', (test, err) => {
      const flattenTitles = (test) => {
        const titles = [test.title];
        while (test.parent.title) {
          titles.push(test.parent.title);
          test = test.parent;
        }
        return titles.reverse().join(' ');
      };

      reports.push({
        name: flattenTitles(test),
        result: false,
        message: err.message,
        stack: err.stack,
      });
    });

    runner.on('end', async () => {
      const results = runner.stats;
      results.reports = reports;

      const windows = await clients.matchAll({
        type: 'window',
        includeUncontrolled: true,
      });

      for (const win of windows) {
        win.postMessage({
          type: 'MOCHA_RESULTS',
          payload: results,
        });
      }

      // Fail installation if the tests don't pass.
      if (results.failures) {
        reject();
      } else {
        resolve();
      }
    });
  });

  event.waitUntil(testsComplete);
}, {once: true}); // Run once since `install` events are dispatched in tests.

importScripts('sw-bundle.js?filter={{ testFilter }}');
